package com.open.rbac.service.sys.impl;

import java.text.ParseException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import com.nimbusds.jose.JOSEException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import com.open.center.jwt.exception.JwtExpiredException;
import com.open.center.jwt.model.JwtToken;
import com.open.center.jwt.model.JwtUser;
import com.open.center.jwt.provider.JwtProvider;
import com.open.rbac.config.security.MeUsernamePasswordAuthenticationToken;
import com.open.rbac.model.UserInfo;
import com.open.rbac.model.vo.sys.LoginVo;
import com.open.rbac.service.sys.ILoginService;


/**
 * 用户登录
 *
 * @author Riche's
 * @since 2022/8/15
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class LoginServiceImpl implements ILoginService {

    private final JwtProvider jwtProvider;

    private final AuthenticationManager authenticationManager;

    public UserInfo login(LoginVo loginVo) {
        MeUsernamePasswordAuthenticationToken token = new MeUsernamePasswordAuthenticationToken(loginVo.getUsername(), loginVo.getPassword());
        Authentication authentication = authenticationManager.authenticate(token);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        return createToken((MeUsernamePasswordAuthenticationToken) authentication);
    }

    @Override
    public UserInfo verify(String token) throws JwtExpiredException, ParseException, JOSEException {
        JwtUser jwtUser = jwtProvider.parseUser(token);
        UserInfo userInfo = new UserInfo();
        userInfo.setId(jwtUser.getUserId());
        userInfo.setUsername(jwtUser.getUsername());
        userInfo.setRealName(jwtUser.getRealName());
        return userInfo;
    }

    @Override
    public UserInfo refresh(String token) throws JwtExpiredException, ParseException, JOSEException {
        JwtUser jwtUser = jwtProvider.parseUser(token);
        MeUsernamePasswordAuthenticationToken authenticationToken =
                new MeUsernamePasswordAuthenticationToken(jwtUser.getUsername(), null);
        authenticationToken.setId(jwtUser.getUserId());
        authenticationToken.setUsername(jwtUser.getUsername());
        authenticationToken.setRealName(jwtUser.getRealName());
        authenticationToken.setEmail(jwtUser.getter().get("email").toString());
        authenticationToken.setPhone(jwtUser.getter().get("phone").toString());
        authenticationToken.setRoleIds(Collections.emptyList());
        return createToken(authenticationToken);
    }

    private UserInfo createToken(MeUsernamePasswordAuthenticationToken token) {
        try {
            Map<String, Object> payload = new HashMap<>();
            payload.put("userId", token.getId());
            payload.put("username", token.getUsername());
            payload.put("roleIds", token.getRoleIds());
            payload.put("realName", token.getRealName());
            payload.put("email", token.getEmail());
            payload.put("phone", token.getPhone());

            UserInfo userInfo = new UserInfo();
            JwtToken accessToken = jwtProvider.createToken(payload);
            userInfo.setId(token.getId());
            userInfo.setAvatar(token.getAvatar());
            userInfo.setUsername(token.getUsername());
            userInfo.setRealName(token.getRealName());
            userInfo.setEmail(token.getEmail());
            userInfo.setPhone(token.getPhone());
            userInfo.setAccessToken(accessToken);
            JwtToken refreshToken = jwtProvider.createToken(payload, jwtProvider.exp(30 * 24L));
            userInfo.setRefreshToken(refreshToken);
            return userInfo;
        } catch (JOSEException e) {
            log.error("::::: {} :::::", e.getMessage());
        }
        return null;
    }

}
